#include "AsioTimerTask.h"

#include <iostream> //for std::cout 

#include <boost/bind/bind.hpp>
#include "TimerTask.h"


namespace frame {
namespace imp {
namespace asio {

AsioTimer::AsioTimer(int timerId, ITimerTask *  task, uint64_t timespan, boost::asio::io_context & ioContext)
: Timer(timerId, task, timespan)
, timer(new boost::asio::steady_timer(ioContext, boost::asio::chrono::milliseconds(timespan)))
{
}
AsioTimer::~AsioTimer() {
    if(timer != nullptr){
        delete timer;
    }
}


void AsioTimer::startTimer(){
    timer->async_wait(boost::bind(&AsioTimer::handleTimer, shared_from_this(), boost::asio::placeholders::error));
}
void AsioTimer::stopTimer(){
    std::cout << "cancel timer" << std::endl;
    timer->cancel();
}
void AsioTimer::handleTimer(const boost::system::error_code& error){
    if(!error){
        timer->expires_after(boost::asio::chrono::milliseconds(getTimeSpan()));
        startTimer();
        if(getTimerTask() != nullptr){
            getTimerTask()->handle(this);
        }
    }
    else if(error == boost::asio::error::operation_aborted){
        std::cout << "timer was cancelled" << std::endl;
    }
    else{
        std::cout << "got an error:" << error << std::endl;
    }
}

std::function<void ()> AsioTimer::TESTStart(){
    return boost::bind(&AsioTimer::TESTHandle, shared_from_this(), 1); 
}
void AsioTimer::TESTHandle(int i){
    std::cout << "TESTHandle from AsioTimer  with enable_shared_from_this" << i << std::endl;
}







AsioTimerTasks::AsioTimerTasks(boost::asio::io_context & ioContext)
:ioContext(ioContext)
{
}
AsioTimerTasks::~AsioTimerTasks()
{
}

void AsioTimerTasks::insertNoFind(int timerId, ITimerTask * task, uint64_t timespan){
    TimerTasks::insertNoFind(std::make_shared<AsioTimer>(timerId, task, timespan, ioContext));
}
bool AsioTimerTasks::insert(int timerId, ITimerTask * task, uint64_t timespan){
    auto timer = std::make_shared<AsioTimer>(timerId, task, timespan, ioContext);
    return TimerTasks::insert(timer);
}

} //end of namespace asio
} //end of namespace imp
} //end of namespace  frame
